package com.signage.signage

import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import androidx.annotation.NonNull
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result
import java.io.OutputStream
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.annotation.RequiresApi
import android.os.PowerManager
class MainActivity : FlutterActivity() {
    companion object {
        private const val TAG = "MainActivity"
        private const val CHANNEL = "com.signage.signage/l2cap"
    }

    private var l2capChannels: MutableMap<String, BluetoothSocket> = mutableMapOf()
    private val closingChannels = mutableMapOf<String, Long>()

    private fun createL2capChannel(call: MethodCall, result: Result) {
        Log.d(TAG, "Creating L2CAP channel with deviceId: ${call.argument<String>("deviceId")}, psm: ${call.argument<Int>("psm")}")
        val deviceId = call.argument<String>("deviceId") ?: run {
            result.error("INVALID_ARGUMENT", "Device ID is required", null)
            return
        }
        val psm = call.argument<Int>("psm") ?: run {
            result.error("INVALID_ARGUMENT", "PSM is required", null)
            return
        }

        Thread {
            try {
                // 1. 确保之前的通道已关闭
                l2capChannels[deviceId]?.let { oldChannel ->
                    try {
                        oldChannel.close()
                    } catch (e: Exception) {
                        Log.e(TAG, "Error closing old channel: ${e.message}")
                    } finally {
                        l2capChannels.remove(deviceId)
                    }
                }
                
                // 2. 等待一小段时间
                Thread.sleep(500)
                
                Log.d(TAG, "Attempting to connect L2CAP channel...")
                val device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceId)
                val channel = device.createInsecureL2capChannel(psm)
                
                // 3. 设置超时
                var connected = false
                val timeoutThread = Thread {
                    Thread.sleep(5000) // 5秒超时
                    if (!connected) {
                        try {
                            channel.close()
                        } catch (e: Exception) {
                            Log.e(TAG, "Error in timeout closure: ${e.message}")
                        }
                    }
                }.apply { start() }
                
                // 4. 尝试连接
                channel.connect()
                connected = true
                
                // 5. 验证连接
                if (channel.isConnected) {
                    l2capChannels[deviceId] = channel
                    Log.d(TAG, "L2CAP channel connected successfully")
                    activity?.runOnUiThread {
                        result.success(null)
                    }
                } else {
                    throw Exception("Channel connected but not showing as connected")
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "Error connecting L2CAP channel: ${e.message}", e)
                activity?.runOnUiThread {
                    result.error("CONNECTION_ERROR", e.message, null)
                }
            }
        }.start()
    }

    private fun sendL2capData(call: MethodCall, result: Result) {
        Log.d(TAG, "Sending data to device: ${call.argument<String>("deviceId")}")
        val deviceId = call.argument<String>("deviceId") ?: run {
            result.error("INVALID_ARGUMENT", "Device ID is required", null)
            return
        }
        val data = call.argument<ByteArray>("data") ?: run {
            result.error("INVALID_ARGUMENT", "Data is required", null)
            return
        }

        Thread {
            try {
                val channel = l2capChannels[deviceId]
                if (channel == null || !channel.isConnected) {
                    activity?.runOnUiThread {
                        result.error("NOT_CONNECTED", "L2CAP channel is not connected", null)
                    }
                    return@Thread
                }

                val channelInfo = mapOf(
                    "isConnected" to channel.isConnected,
                    "maxTransmitPacketSize" to channel.maxTransmitPacketSize,
                    "maxReceivePacketSize" to channel.maxReceivePacketSize,
                    "totalDataSize" to data.size,
                    "remoteDevice" to channel.remoteDevice.address,
                    "remoteDeviceName" to channel.remoteDevice.name,
                    "remoteDeviceType" to channel.remoteDevice.type,
                    "remoteDeviceBondState" to channel.remoteDevice.bondState,
                    "inputStream" to (channel.inputStream != null),
                    "outputStream" to (channel.outputStream != null)
                )
                
                Log.d(TAG, """
                    Detailed channel status:
                    Connection: ${channelInfo["isConnected"]}
                    Max TX Size: ${channelInfo["maxTransmitPacketSize"]} bytes
                    Max RX Size: ${channelInfo["maxReceivePacketSize"]} bytes
                    Data Size: ${channelInfo["totalDataSize"]} bytes
                    Remote Device: ${channelInfo["remoteDevice"]}
                    Device Name: ${channelInfo["remoteDeviceName"]}
                    Device Type: ${getDeviceTypeString(channelInfo["remoteDeviceType"] as Int)}
                    Bond State: ${getBondStateString(channelInfo["remoteDeviceBondState"] as Int)}
                    Has InputStream: ${channelInfo["inputStream"]}
                    Has OutputStream: ${channelInfo["outputStream"]}
                """.trimIndent())

                val outputStream = channel.outputStream
                val CHUNK_SIZE = if (data.size > 96000) {
                    channel.maxTransmitPacketSize
                } else {
                    minOf(8192, channel.maxTransmitPacketSize)
                }
                var offset = 0
                val startTime = System.currentTimeMillis()
                
                while (offset < data.size) {
                    if (!channel.isConnected) {
                        throw Exception("Connection lost during transfer")
                    }

                    val remaining = data.size - offset
                    val chunkSize = minOf(CHUNK_SIZE, remaining)
                    outputStream.write(data, offset, chunkSize)
                    outputStream.flush()
                    offset += chunkSize
                    
                    // Only add delay for smaller data transfers
                    if (data.size <= 96000) {
                        Thread.sleep(100)
                    }
                    
                    val progress = (offset.toFloat() / data.size * 100).toInt()
                    val currentTime = System.currentTimeMillis()
                    val speed = offset / (currentTime - startTime + 1) // KB/s
                    
                     Log.d(TAG, """
                        Transfer status:
                        Progress: $progress%
                        Time:${System.currentTimeMillis()}
                         Speed: $speed KB/s
                         Chunk Size: $chunkSize
                   Remaining: $remaining bytes
                        Channel Connected: ${channel.isConnected}
                 """.trimIndent())
                }

                val totalTime = (System.currentTimeMillis() - startTime) / 1000f
                Log.d(TAG, "Transfer completed in $totalTime seconds")
                
                activity?.runOnUiThread {
                    result.success(null)
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "Error sending data: ${e.message}", e)
                activity?.runOnUiThread {
                    result.error("SEND_ERROR", "Failed to send data: ${e.message}", null)
                }
            }
        }.start()
    }

    private fun closeSpecificChannel(deviceId: String): Boolean {
        // Check if this channel is already being closed
        val closingTimestamp = closingChannels[deviceId]
        if (closingTimestamp != null) {
            val elapsedTime = System.currentTimeMillis() - closingTimestamp
            if (elapsedTime < 5000) {
                Log.d(TAG, "Channel for device $deviceId is already in the process of closing ($elapsedTime ms elapsed)")
                return true
            } else {
                // Timeout occurred, remove from closing list and try again
                Log.w(TAG, "Close operation timed out after $elapsedTime ms for device $deviceId, attempting force close")
                closingChannels.remove(deviceId)
            }
        }
        
        var success = false
        l2capChannels[deviceId]?.let { channel ->
            try {
                // Mark this channel as in the process of closing
                closingChannels[deviceId] = System.currentTimeMillis()
                
                // Use a more aggressive closing strategy
                val forceCloseThread = Thread {
                    try {
                        Log.d(TAG, "Starting force-close watchdog for device $deviceId")
                        Thread.sleep(3000) // Wait 3 seconds for normal close to complete
                        
                        if (closingChannels.containsKey(deviceId)) {
                            // Normal close didn't complete in time
                            Log.w(TAG, "Force-closing socket for device $deviceId")
                            try {
                                // Try to force interrupt any blocked I/O
                                try { channel.inputStream?.close() } catch (e: Exception) {}
                                try { channel.outputStream?.close() } catch (e: Exception) {}
                                try { channel.close() } catch (e: Exception) {}
                                
                                // For extra measure, try to close at Java socket level
                                val socketField = BluetoothSocket::class.java.getDeclaredField("mSocket")
                                socketField.isAccessible = true
                                val socket = socketField.get(channel)
                                if (socket != null && socket.javaClass.name.contains("Socket")) {
                                    val closeMethod = socket.javaClass.getMethod("close")
                                    closeMethod.invoke(socket)
                                    Log.d(TAG, "Invoked underlying socket.close() via reflection")
                                }
                            } catch (e: Exception) {
                                Log.e(TAG, "Force-close failed: ${e.message}")
                            } finally {
                                // Always make sure we clean up our tracking
                                closingChannels.remove(deviceId)
                                l2capChannels.remove(deviceId)
                            }
                        }
                    } catch (e: Exception) {
                        Log.e(TAG, "Error in force-close watchdog: ${e.message}")
                    }
                }
                forceCloseThread.isDaemon = true // Don't prevent app exit
                forceCloseThread.start()
                
                // Try normal close procedure
                try {
                    // First cancel any pending I/O by closing streams
                    try {
                        Log.d(TAG, "Closing input stream for device $deviceId")
                        channel.inputStream?.close()
                    } catch (e: Exception) {
                        Log.e(TAG, "Error closing input stream: ${e.message}")
                    }
                    
                    try {
                        Log.d(TAG, "Closing output stream for device $deviceId")
                        channel.outputStream?.close()
                    } catch (e: Exception) {
                        Log.e(TAG, "Error closing output stream: ${e.message}")
                    }
                    
                    // Wait a bit for streams to close
                    Thread.sleep(200)
                    
                    // Now close the socket
                    Log.d(TAG, "Closing channel for device $deviceId")
                    channel.close()
                    
                    // Wait a bit to let close operation proceed
                    Thread.sleep(300)
                    
                    // Check if really closed
                    if (!channel.isConnected) {
                        Log.d(TAG, "Channel successfully disconnected for device $deviceId")
                        success = true
                        // Clean up our tracking
                        closingChannels.remove(deviceId)
                    } else {
                        Log.w(TAG, "Channel still connected after close attempt for device $deviceId")
                        // Let the force-close watchdog handle it
                    }
                } catch (e: Exception) {
                    Log.e(TAG, "Error during normal close for device $deviceId: ${e.message}")
                    // Let the force-close watchdog handle it
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "Error initiating channel cleanup for device $deviceId: ${e.message}")
            } finally {
                // Remove from active channels map
                l2capChannels.remove(deviceId)
            }
        } ?: run {
            Log.d(TAG, "No active L2CAP channel found for device: $deviceId")
            success = true  // No channel to close means success
        }
        
        return success
    }

    private fun closeL2capChannel(call: MethodCall, result: Result) {
        val deviceId = call.argument<String>("deviceId") ?: run {
            result.error("INVALID_ARGUMENT", "Device ID is required", null)
            return
        }

        Log.d(TAG, "Closing L2CAP channel for device: $deviceId")
        Thread {
            try {
                val success = closeSpecificChannel(deviceId)
                if (success) {
                    Log.d(TAG, "L2CAP channel closed successfully for device: $deviceId")
                    activity?.runOnUiThread {
                        result.success(null)
                    }
                } else {
                    Log.w(TAG, "L2CAP channel close operation timed out for device: $deviceId")
                    activity?.runOnUiThread {
                        result.error("CLOSE_TIMEOUT", "L2CAP channel close operation timed out", null)
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "Error closing L2CAP channel: ${e.message}", e)
                activity?.runOnUiThread {
                    result.error("CLOSE_ERROR", e.message, null)
                }
            }
        }.start()
    }

    private fun getL2capMtu(call: MethodCall, result: Result) {
        val deviceId = call.argument<String>("deviceId") ?: run {
            activity?.runOnUiThread {
                result.error("INVALID_ARGUMENT", "Device ID is required", null)
            }
            return
        }

        Thread {
            try {
                val channel = l2capChannels[deviceId]
                if (channel == null || !channel.isConnected) {
                    activity?.runOnUiThread {
                        result.error("NOT_CONNECTED", "L2CAP channel is not connected for device: $deviceId", null)
                    }
                    return@Thread
                }

                // 获取发送和接收的MTU大小
                val sendMtu = channel.maxTransmitPacketSize
                val receiveMtu = channel.maxReceivePacketSize
                
                // 只包含确定可用的参数
                val connectionParams = mapOf(
                    "deviceId" to deviceId,
                    "sendMtu" to sendMtu,
                    "receiveMtu" to receiveMtu,
                    "isConnected" to channel.isConnected
                )

                Log.d(TAG, "L2CAP MTU info for device $deviceId:")
                Log.d(TAG, "Send MTU: $sendMtu bytes")
                Log.d(TAG, "Receive MTU: $receiveMtu bytes")
                Log.d(TAG, "Connection Parameters: $connectionParams")

                activity?.runOnUiThread {
                    result.success(connectionParams)
                }

            } catch (e: Exception) {
                Log.e(TAG, "Error getting L2CAP MTU: ${e.message}", e)
                activity?.runOnUiThread {
                    result.error(
                        "MTU_ERROR",
                        "Failed to get L2CAP MTU: ${e.message}",
                        e.toString()
                    )
                }
            }
        }.start()
    }

    private fun isIgnoringBatteryOptimizations(call: MethodCall, result: Result) {
        result.success(if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            true // 低于 API 23 返回 true
        } else {
            try {
                val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
                powerManager.isIgnoringBatteryOptimizations(packageName)
            } catch (e: Exception) {
                Log.e(TAG, "Error checking battery optimizations: ${e.message}", e)
                true
            }
        })
    }

    private var requestIgnoreBatteryOptimizationsCall : Result? = null
    fun requestIgnoreBatteryOptimizations(call: MethodCall, result: Result) {
        try {
            val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
                data = Uri.parse("package:$packageName")
            }
            startActivity(intent)
            requestIgnoreBatteryOptimizationsCall = result
        } catch (e: Exception) {
            e.printStackTrace()
            activity?.runOnUiThread {
                result.error("REQUEST_IGNORE_BATTERY_OPTIMIZATIONS_ERROR", e.message, null)
            }
        }
    }

    override fun onResume() {
        super.onResume()
        requestIgnoreBatteryOptimizationsCall?.success(null)
    }

    // 辅助函数：将设备类型代码转换为可读字符串
    private fun getDeviceTypeString(type: Int): String = when (type) {
        BluetoothDevice.DEVICE_TYPE_CLASSIC -> "CLASSIC"
        BluetoothDevice.DEVICE_TYPE_LE -> "LE"
        BluetoothDevice.DEVICE_TYPE_DUAL -> "DUAL"
        BluetoothDevice.DEVICE_TYPE_UNKNOWN -> "UNKNOWN"
        else -> "UNDEFINED"
    }

    // 辅助函数：将绑定状态代码转换为可读字符串
    private fun getBondStateString(state: Int): String = when (state) {
        BluetoothDevice.BOND_NONE -> "NONE"
        BluetoothDevice.BOND_BONDING -> "BONDING"
        BluetoothDevice.BOND_BONDED -> "BONDED"
        else -> "UNKNOWN"
    }

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            when (call.method) {
                "createL2capChannel" -> createL2capChannel(call, result)
                "sendL2capData" -> sendL2capData(call, result)
                "closeL2capChannel" -> closeL2capChannel(call, result)
                "getL2capMtu" -> getL2capMtu(call, result)
                "requestIgnoreBatteryOptimizations" -> requestIgnoreBatteryOptimizations(call, result)
                "isIgnoringBatteryOptimizations" -> isIgnoringBatteryOptimizations(call, result)
                else -> result.notImplemented()
            }
        }
    }
} 
